package com.android.support.lib.universal.view.gamepad;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.android.support.lib.universal.R;
import com.android.support.lib.universal.listenner.JoystickListener;

/**
 * 滚珠方向键
 * 注意：底盘的宽度和高度占自身控件宽度和高度的2/3(居中),滚珠占1/3,且滚珠的滚动无法超过控件本身的宽度和高度(初始居中)
 * 控件的宽度和高度相等，且以较小的那个为标准。
 *
 * @author 彭治铭
 */
public class JoystickView extends View {

    //底盘
    private Bitmap mJoystickBG;
    //滚珠
    private Bitmap mJoystickRock;
    private Paint mPaint;

    //控件的宽带
    private int mWidth;
    //控件的高度
    private int mHeight;
    //位图偏移左边的位置
    private int paddingLeft = 0;
    //位图偏移顶部的位置
    private int paddingTop = 0;

    //中心坐标X
    private double mCenterX;
    //中心坐标Y
    private double mCenterY;
    //滚珠圆心X
    private double mRockCenterX;
    //滚珠圆心Y
    private double mRockCenterY;

    //低盘半径
    private double mOuterRadius;
    //滚珠半径
    private double mInnerRadius;

    private boolean mIsMotion = false;

    private JoystickListener mJoystickListener;

    public JoystickView(Context context) {
        this(context, null);
    }

    public JoystickView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public JoystickView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mPaint = new Paint();
    }

    //设置滚珠监听事件
    public void setJoystickListener(JoystickListener joystickListener) {
        mJoystickListener = joystickListener;
    }

    @Override
    public void layout(int left, int top, int right, int bottom) {

        if (null == mJoystickBG) {
            mWidth = right - left;
            mHeight = bottom - top;
            mWidth = mWidth - 2 * paddingLeft;
            mHeight = mHeight - 2 * paddingLeft;
            mOuterRadius = mWidth / 3;
            mInnerRadius = mWidth / 6;
            mCenterX = mWidth / 2;
            mCenterY = mHeight / 2;

            mRockCenterX = mCenterX;
            mRockCenterY = mCenterY;

            Resources res = getResources();
            //滚珠底盘图片
            mJoystickBG = BitmapFactory.decodeResource(res, R.drawable.lib_gamepad_mjoystickbg);
            //滚珠图片
            mJoystickRock = BitmapFactory.decodeResource(res,
                    R.drawable.lib_gamepad_mjoystickrock);
            if (isInEditMode()) {
                return;
            }
            // 低盘的大小
            mJoystickBG = Bitmap.createScaledBitmap(mJoystickBG,
                    Math.round((float) (mOuterRadius * 2)),
                    Math.round((float) (mOuterRadius * 2)), true);
            // 滚珠大小
            mJoystickRock = Bitmap.createScaledBitmap(mJoystickRock,
                    Math.round((float) (mInnerRadius * 2)),
                    Math.round((float) (mInnerRadius * 2)), true);
        }

        super.layout(left, top, right, bottom);
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (isInEditMode()) {
            return;
        }
        
        // 底盘(固定不变，画在画布中心)
        canvas.drawBitmap(mJoystickBG,
                Math.round(mCenterX - mJoystickBG.getWidth() / 2 + paddingLeft),
                Math.round(mCenterY - mJoystickBG.getHeight() / 2 + paddingLeft), mPaint);
        // 滚珠
        canvas.drawBitmap(mJoystickRock,
                Math.round(mRockCenterX - mInnerRadius + paddingLeft),
                Math.round(mRockCenterY - mInnerRadius + paddingLeft), mPaint);
        super.onDraw(canvas);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        float x = event.getX() - paddingLeft;
        float y = event.getY() - paddingLeft;

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_POINTER_DOWN:
                return false;
            case MotionEvent.ACTION_DOWN:
                if (Math.sqrt(Math.pow((mCenterX - x), 2)
                        + Math.pow((mCenterY - y), 2)) > mOuterRadius) {
                    return false;
                }
                mIsMotion = true;
                //事件传递
                new MotionTask().start();
                break;
            case MotionEvent.ACTION_MOVE:

                if (Math.sqrt(Math.pow((mCenterX - x), 2)
                        + Math.pow((mCenterY - y), 2)) < mWidth / 4) {
                    mRockCenterX = x;
                    mRockCenterY = y;
                } else {
                    double rad = getRad(mCenterX, mCenterY, x, y);
                    getXY(mCenterX, mCenterY, mWidth / 4, rad);
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                return false;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mRockCenterX = mCenterX;
                mRockCenterY = mCenterY;
                mIsMotion = false;
                break;
        }

        invalidate();
        return true;
    }

    private double getRad(double px1, double py1, float px2, float py2) {
        double x = px2 - px1;
        double y = py2 - py1;
        double xx = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        double cosA = x / xx;
        double rad = Math.acos(cosA);
        return py2 < py1 ? -rad : rad;
    }

    private void getXY(double centerX, double centerY, double radius, double rad) {
        mRockCenterX = radius * Math.cos(rad) + mCenterX;
        mRockCenterY = radius * Math.sin(rad) + mCenterY;
    }

    private class MotionTask extends Thread {
        @Override
        public void run() {
            //震动音效
            GamepadConfig.STYLE();
            while (mIsMotion) {
                float x = (float) ((mRockCenterX - mCenterX) / mWidth / 4);
                float y = (float) ((mRockCenterY - mCenterY) / mWidth / 4);
                x = x > 0.999 ? 1 : x;
                x = x < -0.999 ? -1 : x;
                y = y > 0.999 ? 1 : y;
                y = y < -0.999 ? -1 : y;
                x = x < 0.033 && x > -0.033 ? 0 : x;
                y = y < 0.033 && y > -0.033 ? 0 : y;

                final float x1 = x;
                final float y1 = y;
                post(new Runnable() {

                    @Override
                    public void run() {
                        if (null != mJoystickListener) {
                            MotionEvent event = MotionEvent.obtain(
                                    System.currentTimeMillis(),
                                    System.currentTimeMillis(),
                                    MotionEvent.ACTION_MOVE, x1, y1, 0, 0, 0,
                                    0, 0, 0, 0);
                            mJoystickListener.onJoystikMotionEvent(event);
                            event.recycle();
                        }
                    }

                });

                try {
                    Thread.sleep(40);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
